package morrislabs.controls
{
//		<components:NumericInput 
//			width="25" height="100%" borderStyle="none" backgroundColor="#B9F4F1" alpha=".5" 
//			textAlign="center" paddingTop="2" restrict="0-9" focusThickness="0" focusRect="0"
//			maxChars="2" 
//			autoAdvance="true"
//			minValue="0"
//			maxValue="99"
//			text="5" fontSize="11"/>
	
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	import mx.controls.TextInput;
	import mx.events.FocusRequestDirection;

	public class NumericInput extends TextInput
	{
		private var _autoAdvance:Boolean;
		private var _minValue:int;
		private var _maxValue:int;
		private var _initValue:int;
		private var _value:int;
		private var _isLastInput:Boolean;  
		
		public function NumericInput()
		{
			super();
			
			// set defaults
			restrict = "0-9";
			width = 25;
			percentHeight = 100;
			alpha = 0.5;
			doubleClickEnabled = false;
			setStyle("borderStyle","none");
			setStyle("backgroundColor","#B9F4F1");
			setStyle("textAlign","right");
			setStyle("paddingTop",2);
			setStyle("focusThickness",0);
			setStyle("focusRect",0);
			setStyle("fontSize",11);
						
			autoAdvance = true;
			minValue = 0;
			maxValue = 99;
			maxChars = 2;
			isLastInput = false;

			addEventListener(Event.CHANGE, changeEvents);
			addEventListener(FocusEvent.FOCUS_IN, focusInEvents);	
			addEventListener(FocusEvent.FOCUS_OUT, focusOutEvents);
			addEventListener(KeyboardEvent.KEY_DOWN, keyDownEvents);
		}
		
		override public function set text( newValue:String ) : void {
    		super.text = addLeadingZeros(newValue);
    		_value = parseInt(super.text);
		}
		
		override public function setStyle(styleProp:String, newValue:*) : void {
    		super.setStyle(styleProp, newValue);
    		
    		if (styleProp == "fontSize") {
    			this.width = ((newValue as int)+2) * this.maxChars;
    			//this.width = 20;
	   		}
		}		
		
        private function changeEvents(e:Event):void {
        	if (atEndOfInput() && !isLastInput) {
				changeFocus(mx.events.FocusRequestDirection.FORWARD);
        	}	
        }
        
        private function atEndOfInput():Boolean {
        	return (this.textField.caretIndex == this.maxChars);
        }
        
        private function atStartOfInput():Boolean {
        	return (this.textField.caretIndex == 0);
        }        
        
        private function changeFocus(direction:String):void {
     		if (this.isValid()) {
    			if (_autoAdvance) {
					try {
						focusManager.moveFocus(direction);
					} catch (erObject:Error) {
						// catch
					}
    			}
    		} else {
    			selectAll();
    		}
         }
        
       	private function focusOutEvents( event:FocusEvent ) : void {
       		if (isValid()) {
       			this.text = addLeadingZeros(this.text);
       		} else {
       			setFocus();
       		}	
       	}
       	
       	private function focusInEvents( event:FocusEvent ) : void {
   			selectAll();
       	}       	
        
       	private function keyDownEvents( event:KeyboardEvent ) : void {
       		var newValue:int = _value;
       		var step:int = ((_maxValue+1)-_minValue)/2;
       		
       		switch(event.keyCode) {
       			case Keyboard.UP:
       					newValue++;
       					if (newValue > _maxValue)
       						newValue = _minValue;
       					this.value = newValue;
       					selectAll();
					break;
					
       			case Keyboard.PAGE_UP:
       					newValue += step;
       					if (newValue > _maxValue)
       						newValue = newValue - _maxValue - 1;
       					this.value = newValue;
       					selectAll();
					break;					
       				
       			case Keyboard.DOWN:
       					newValue--;
       					if (newValue < _minValue)
       						newValue = _maxValue;
       					this.value = newValue;
       					selectAll();    					
       				break;
       				
       			case Keyboard.PAGE_DOWN:
       					newValue -= step;
       					if (newValue < _minValue)
       						newValue = _minValue - newValue;
       					this.value = newValue;
       					selectAll();
					break;					       				
       				
       			case Keyboard.RIGHT:
  						changeFocus(mx.events.FocusRequestDirection.FORWARD);
  						//selectAll();
       				break;	
       				
       			case Keyboard.LEFT:
   						changeFocus(mx.events.FocusRequestDirection.BACKWARD);
  						//selectAll();
       				break;	 
      				
       			case Keyboard.ENTER:
       					
  						changeFocus(mx.events.FocusRequestDirection.FORWARD);
  						
       				break;	
       				      				
       		}
       	}

        
        private function addLeadingZeros(newValue:String):String {
        	var newValue:String;
        	var emptyspaces:int;
        	
         	emptyspaces = this.maxChars - newValue.length;
        	
        	while ( emptyspaces-- > 0 ) {
        		newValue = "0" + newValue;
        	}
        	
        	return newValue;
        }
        
        
        private function isValid(...args):Boolean {
        	var thisValue:int;
        	
        	switch (args.length) {
        		case 0:  
        			thisValue = this._value;
        			break;
        		case 1:
        		  	if (args[0] is Number) {
        				thisValue = args[0] as Number;
        		  	} else {
        		  		return false;
        		  	}
        		  	break;
        		default:
        			return false;
        	}
        	
        	return (thisValue >= _minValue && thisValue <= _maxValue);
        }        
        
        
        public function selectAll():void {
        	setSelection(this.length, 0);
        }
        
   
        public function get value():int {
        	return _value;
        }
		
		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]     		
        public function set value(newValue:int):void {
        	if (isValid(newValue)) {
        		this.text = newValue.toString();
        	}
        }

	 
		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]
		/**
	     *  If set to true, focus will automatically fire an event
	     * to move to the next field in the tab order.
	     *
	     *  @default true
	     */
		public function set autoAdvance( newValue:Boolean ) : void
		{
			_autoAdvance = newValue;
		}
		 
		public function get autoAdvance() : Boolean
		{
			return _autoAdvance;
		}
		

		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]
		/**
	     *  sets the minimum value allowable.
	     *  @default 0
	     */
		public function set minValue( newValue:int ) : void
		{
			_minValue = newValue;
		}
		 
		public function get minValue() : int
		{
			return _minValue;
		}
				
				
		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]
		/**
	     *  sets the maximum value allowable.
	     *  @default 9
	     */
		public function set maxValue( newValue:int ) : void
		{
			_maxValue = newValue;
			this.maxChars = _maxValue.toString().length;
		}
		 
		public function get maxValue() : int
		{
			return _maxValue;
		}	
		
		
		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]
		/**
	     *  sets the default value.
	     *  @default null
	     */
		public function set initValue( newValue:int ) : void
		{
			_initValue = newValue;
		}
		 
		public function get initValue() : int
		{
			return _initValue;
		}
		
		
		[Bindable("change")]
	    [Inspectable(category="General", defaultValue="true")]
		/**
	     *  sets the default value.
	     *  @default null
	     */
		public function set isLastInput( newValue:Boolean ) : void
		{
			_isLastInput = newValue;
		}
		 
		public function get isLastInput() : Boolean
		{
			return _isLastInput;
		}			
	}				
		
}